#!/usr/bin/env python
# -*- coding: UTF-8 -*-
import os
import time
import json
import hashlib
import datetime
import requests
from auth import Auth
from dotenv import load_dotenv, find_dotenv
from flask import Flask, request, jsonify, render_template
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate

# const
# 随机字符串，用于签名生成加密使用
NONCE_STR = "13oEviLbrTo458A3NjrOwS70oTOXVOAm"

# 从 .env 文件加载环境变量参数
load_dotenv(find_dotenv())

# 初始化 flask 网页应用
app = Flask(__name__, static_url_path="/public", static_folder="./public")

# 初始化数据库
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///yukong.db'  # 使用 SQLite 数据库
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemy(app)

# 迁移数据库
migrate = Migrate(app, db)

# 获取环境变量
APP_ID = os.getenv("APP_ID")
APP_SECRET = os.getenv("APP_SECRET")
FEISHU_HOST = os.getenv("FEISHU_HOST")

# 创建模型
class User(db.Model):
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    username = db.Column(db.String(80), nullable=False)
    avatarUrl = db.Column(db.String(255), nullable=False)
    enable = db.Column(db.String(10), nullable=True)
    create_time = db.Column(db.DateTime, nullable=True, default=datetime.datetime.utcnow)
    description = db.Column(db.String(500), nullable=True)

    def __repr__(self):
        return f'<User {self.username}>'

class Platform(db.Model):
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    platform = db.Column(db.String(80), unique=True, nullable=False)
    enable = db.Column(db.String(10), nullable=True)
    author = db.Column(db.String(80), nullable=True)
    create_time = db.Column(db.DateTime, nullable=True, default=datetime.datetime.utcnow)
    description = db.Column(db.String(500), nullable=True)

    def __repr__(self):
        return f'<Platform {self.platform}>'

class Device(db.Model):
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    host = db.Column(db.String(80), nullable=False)
    port = db.Column(db.String(10), nullable=False)
    method = db.Column(db.String(10), nullable=False)
    platform = db.Column(db.String(10), nullable=False)
    status = db.Column(db.String(10), nullable=True)
    enable = db.Column(db.String(10), nullable=True)
    author = db.Column(db.String(80), nullable=True)
    create_time = db.Column(db.DateTime, nullable=True, default=datetime.datetime.utcnow)
    description = db.Column(db.String(500), nullable=True)

    def __repr__(self):
        return f'<Device {self.platform}>'

# 应用出现错误时，实用flask的errorhandler装饰器实现应用错误处理
@app.errorhandler(Exception)
def auth_error_handler(ex):
    response = jsonify(message=str(ex))
    response.status_code = (
        ex.response.status_code if isinstance(ex, requests.HTTPError) else 500
    )
    return response

# 用获取的环境变量初始化Auth类，由APP ID和APP SECRET获取access token，进而获取jsapi_ticket
auth = Auth(FEISHU_HOST, APP_ID, APP_SECRET)

# 默认的主页路径
@app.route("/", methods=["GET"])
def get_home():
    # 打开本网页应用执行的第一个函数
    # 展示主页
    return render_template("index.html")

@app.route("/home", methods=["GET"])
def home():
    return render_template("home/index.html")

@app.route("/home/view", methods=["GET"])
def home_view():
    return render_template("home/view.html")

@app.route("/device", methods=["GET"])
def device():
    return render_template("device/index.html")

@app.route("/device/add", methods=["GET", "POST"])
def device_add():
    if request.method == "GET":
        return render_template("device/add.html")
    host = request.form.get('host')
    port = request.form.get('port')
    method = request.form.get('method')
    platform = request.form.get('platform')
    description = request.form.get('description')
    if not host:
        return jsonify({
            'code': 100,
            'msg': 'Missing host parameter',
        })
    if not port:
        return jsonify({
            'code': 100,
            'msg': 'Missing port parameter',
        })
    data = {'code': 0, 'msg': 'success'}
    new_device = Device(host=host, port=port, method=method, platform=platform, description=description)
    db.session.add(new_device)
    db.session.commit()
    return jsonify(data)

@app.route("/device/list", methods=["GET"])
def device_list():
    return render_template("device/list.html")

@app.route("/device/get_list", methods=["GET"])
def device_get_list():
    devices = Device.query.all()
    data = []
    for item in devices:
        data.append({
            'id': item.id,
            'host': item.host,
            'port': item.port,
            'method': item.method,
            'enable': item.enable,
            'platform': item.platform,
            'author': item.author,
            'create_time': item.create_time.strftime('%Y-%m-%d %H:%M:%S'),
            'description': item.description,
        })
    return jsonify({
        'code': 0,
        'msg': 'success',
        'count': len(data),
        'data': data,
    })

@app.route("/platform", methods=["GET"])
def platform():
    return render_template("platform/index.html")

@app.route("/platform/add", methods=["GET", "POST"])
def platform_add():
    if request.method == "GET":
        return render_template("platform/add.html")
    platform = request.form.get('platform')
    enable = request.form.get('enable')
    description = request.form.get('description')
    if not platform:
        return jsonify({
            'code': 100,
            'msg': 'Missing platform parameter',
        })
    data = {'code': 0, 'msg': 'success'}
    new_platform = Platform(platform=platform, enable=enable, description=description)
    db.session.add(new_platform)
    db.session.commit()
    return jsonify(data)

@app.route("/platform/list", methods=["GET"])
def platform_list():
    return render_template("platform/list.html")

@app.route("/platform/get_list", methods=["GET"])
def platform_get_list():
    platforms = Platform.query.all()
    data = []
    for item in platforms:
        data.append({
            'id': item.id,
            'platform': item.platform,
            'enable': item.enable,
            'author': item.author,
            'create_time': item.create_time,
            'description': item.description,
        })
    return jsonify({
        'code': 0,
        'msg': 'success',
        'count': len(data),
        'data': data,
    })

# 获取并返回接入方前端将要调用的config接口所需的参数
@app.route("/get_config_parameters", methods=["GET"])
def get_config_parameters():    
    # 接入方前端传来的需要鉴权的网页url
    url = request.args.get("url")
    # 初始化Auth类时获取的jsapi_ticket
    ticket = auth.get_ticket()
    # 当前时间戳，毫秒级
    timestamp = int(time.time()) * 1000
    # 拼接成字符串 
    verify_str = "jsapi_ticket={}&noncestr={}&timestamp={}&url={}".format(
        ticket, NONCE_STR, timestamp, url
    )
    # 对字符串做sha1加密，得到签名signature
    signature = hashlib.sha1(verify_str.encode("utf-8")).hexdigest()
    # 将鉴权所需参数返回给前端
    return jsonify(
        {
            "appid": APP_ID,
            "signature": signature,
            "noncestr": NONCE_STR,
            "timestamp": timestamp,
        }
    )


if __name__ == "__main__":
    # 创建数据库
    with app.app_context():
        # 删除所有表
        # db.drop_all()
        # 创建所有表
        db.create_all()
    # 以debug模式运行本网页应用
    # debug模式能检测服务端模块的代码变化，如果有修改会自动重启服务
    app.run(host="0.0.0.0", port=3000, debug=True)
